/*
 * Copyright 2024 ywcai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

`include "../core/defines.v"
`include "axi_defines.v"
`timescale 1ns/1ps

module axi_slave_mux(
	input	wire				s_we_i,
	input	wire[`MemAddrBus]	s_addr_i,
	input	wire[`RegDataBus]	s_wr_data_i,
	input	wire[7:0]			s_strb_i,

	input	wire				s0_sel_i,
	input	wire				s1_sel_i,
	input	wire				s2_sel_i,
	input	wire				s3_sel_i,
	input	wire				s4_sel_i,
	input	wire				s5_sel_i,
	input	wire				s6_sel_i,
	input	wire				s7_sel_i,

	input	wire[`RegDataBus]	s0_rd_data_i,
	input	wire[1:0]			s0_errcode_i,
	input	wire[`RegDataBus]	s1_rd_data_i,
	input	wire[1:0]			s1_errcode_i,
	input	wire[`RegDataBus]	s2_rd_data_i,
	input	wire[1:0]			s2_errcode_i,
	input	wire[`RegDataBus]	s3_rd_data_i,
	input	wire[1:0]			s3_errcode_i,
	input	wire[`RegDataBus]	s4_rd_data_i,
	input	wire[1:0]			s4_errcode_i,
	input	wire[`RegDataBus]	s5_rd_data_i,
	input	wire[1:0]			s5_errcode_i,
	input	wire[`RegDataBus]	s6_rd_data_i,
	input	wire[1:0]			s6_errcode_i,
	input	wire[`RegDataBus]	s7_rd_data_i,
	input	wire[1:0]			s7_errcode_i,

    output  wire                s0_we_o,
	output	wire[`MemAddrBus]	s0_addr_o,
    output	wire[`RegDataBus]	s0_wr_data_o,
    output	wire[7:0]			s0_strb_o,
    output  wire                s1_we_o,
    output	wire[`MemAddrBus]	s1_addr_o,
    output	wire[`RegDataBus]	s1_wr_data_o,
    output	wire[7:0]			s1_strb_o,
    output  wire                s2_we_o,
    output	wire[`MemAddrBus]	s2_addr_o,
    output	wire[`RegDataBus]	s2_wr_data_o,
    output	wire[7:0]			s2_strb_o,
    output  wire                s3_we_o,
    output	wire[`MemAddrBus]	s3_addr_o,
    output	wire[`RegDataBus]	s3_wr_data_o,
    output	wire[7:0]			s3_strb_o,
    output  wire                s4_we_o,
    output	wire[`MemAddrBus]	s4_addr_o,
    output	wire[`RegDataBus]	s4_wr_data_o,
    output	wire[7:0]			s4_strb_o,
    output  wire                s5_we_o,
    output	wire[`MemAddrBus]	s5_addr_o,
    output	wire[`RegDataBus]	s5_wr_data_o,
    output	wire[7:0]			s5_strb_o,
    output  wire                s6_we_o,
    output	wire[`MemAddrBus]	s6_addr_o,
    output	wire[`RegDataBus]	s6_wr_data_o,
    output	wire[7:0]			s6_strb_o,
    output  wire                s7_we_o,
    output	wire[`MemAddrBus]	s7_addr_o,
    output	wire[`RegDataBus]	s7_wr_data_o,
    output	wire[7:0]			s7_strb_o,

	output	wire[`RegDataBus]	s_rd_data_o,
	output	wire[1:0]			s_errcode_o
	);

	assign s0_we_o = s0_sel_i & s_we_i;
	assign s1_we_o = s1_sel_i & s_we_i;
	assign s2_we_o = s2_sel_i & s_we_i;
	assign s3_we_o = s3_sel_i & s_we_i;
	assign s4_we_o = s4_sel_i & s_we_i;
	assign s5_we_o = s5_sel_i & s_we_i;
	assign s6_we_o = s6_sel_i & s_we_i;
	assign s7_we_o = s7_sel_i & s_we_i;

	assign s0_addr_o = ({`MEM_ADDR_WIDTH{s0_sel_i}} & (s_addr_i - `TIMER_BASE));
	assign s1_addr_o = ({`MEM_ADDR_WIDTH{s1_sel_i}} & (s_addr_i - `ROM_BASE));
	assign s2_addr_o = ({`MEM_ADDR_WIDTH{s2_sel_i}} & (s_addr_i - `UART_BASE));
	assign s3_addr_o = ({`MEM_ADDR_WIDTH{s3_sel_i}} & (s_addr_i - `GPIO_BASE));
	assign s4_addr_o = ({`MEM_ADDR_WIDTH{s4_sel_i}} & (s_addr_i - `SDRAM_BASE));
	assign s5_addr_o = `MEM_ADDR_WIDTH'hffffffffff;
	assign s6_addr_o = `MEM_ADDR_WIDTH'hffffffffff;
	assign s7_addr_o = `MEM_ADDR_WIDTH'hffffffffff;

	assign s0_wr_data_o = ({`XLEN{s0_sel_i}} & s_wr_data_i);
	assign s1_wr_data_o = ({`XLEN{s1_sel_i}} & s_wr_data_i);
	assign s2_wr_data_o = ({`XLEN{s2_sel_i}} & s_wr_data_i);
	assign s3_wr_data_o = ({`XLEN{s3_sel_i}} & s_wr_data_i);
	assign s4_wr_data_o = ({`XLEN{s4_sel_i}} & s_wr_data_i);
	assign s5_wr_data_o = `XLEN'hffffffffffffffff;
	assign s6_wr_data_o = `XLEN'hffffffffffffffff;
	assign s7_wr_data_o = `XLEN'hffffffffffffffff;

	assign s0_strb_o = ({8{s0_sel_i}} & s_strb_i);
	assign s1_strb_o = ({8{s1_sel_i}} & s_strb_i);
	assign s2_strb_o = ({8{s2_sel_i}} & s_strb_i);
	assign s3_strb_o = ({8{s3_sel_i}} & s_strb_i);
	assign s4_strb_o = ({8{s4_sel_i}} & s_strb_i);
	assign s5_strb_o = ({8{s5_sel_i}} & s_strb_i);
	assign s6_strb_o = ({8{s6_sel_i}} & s_strb_i);
	assign s7_strb_o = ({8{s7_sel_i}} & s_strb_i);

	assign s_rd_data_o = ({`XLEN{s0_sel_i}} & s0_rd_data_i)
		| ({`XLEN{s1_sel_i}} & s1_rd_data_i)
		| ({`XLEN{s2_sel_i}} & s2_rd_data_i)
		| ({`XLEN{s3_sel_i}} & s3_rd_data_i)
		| ({`XLEN{s4_sel_i}} & s4_rd_data_i)
		| ({`XLEN{s5_sel_i}} & s5_rd_data_i)
		| ({`XLEN{s6_sel_i}} & s6_rd_data_i)
		| ({`XLEN{s7_sel_i}} & s7_rd_data_i);

	assign s_errcode_o = ({2{s0_sel_i}} & s0_errcode_i)
		| ({2{s1_sel_i}} & s1_errcode_i)
		| ({2{s2_sel_i}} & s2_errcode_i)
		| ({2{s3_sel_i}} & s3_errcode_i)
		| ({2{s4_sel_i}} & s4_errcode_i)
		| ({2{s5_sel_i}} & s5_errcode_i)
		| ({2{s6_sel_i}} & s6_errcode_i)
		| ({2{s7_sel_i}} & s7_errcode_i);

endmodule
